package com.lwlk.util.flow;

import com.lwlk.util.functional.*;
import com.lwlk.util.tuple.Tuple2;

import java.util.Optional;

// 处理 try-catch 逻辑的帮助类
public class Try {

    // 执行0参数过程，忽略异常
    public static void ignoreWith(Procedure0 proc) {
        try { proc.call(); } catch (Exception e) { }
    }

    // 执行0参数生产器，忽略异常，结果为Optional
    public static <R> Optional<R> ignoreGet(Produce<R> func) {
        R r = null;
        try { r = func.call(); } catch(Exception e) { }
        return Optional.ofNullable(r);
    }

    // 抑制异常 将异常转化为运行时异常
    public static <R> R restrainGet(Produce<R> proc) {
        try {
            return proc.call();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 抑制异常 将异常转化为指定的运行时异常
    // 方便在类似 Spring 的容器中利用全局异常捕获机制 将特定业务的异常封装起来
    // 举个栗子
    // int[] arr = restrainGet(() -> new[-1], MollocArraySpaceException::new)
    // 这个异常是自定义的（申请数组内存时异常 就是这么土...）
    // 同时 MollocArraySpaceException <  RuntimeException
    // 并且 具有 String -> MollocArraySpaceException 的构造函数
    // 很明显这个 msg 可以仅用于适配类型 而在构造时传入自定义的的msg
    public static <R, Ex extends RuntimeException> R restrainGet(Produce<R> proc, Method1<Ex, String> method) {
        try {
            return proc.call();
        } catch (Exception e) {
            throw method.call(e.getMessage());
        }
    }

    // 执行0参数过程，返回可能出现的异常
    public static Optional<Exception> catchWith(Procedure0 proc) {
        Exception ee = null;
        try { proc.call(); } catch (Exception e) { ee = e; }
        return Optional.ofNullable(ee);
    }

    // 抑制异常 返回值不是值就是异常 配合retain方法搞事情
    // 举个栗子：
    // restrain(() -> somethingMayThrowException()).retainR()
    //                                             .map((data) -> applyIt(data))
    //                                             .orelse(defaultdata)
    public static <T> Tuple2<Exception, T> restrain(Produce<T> produce) {
        try {
            return Tuple2.with(null, produce.call());
        } catch (Exception e) {
            return Tuple2.with(e, null);
        }
    }

    // 尝试执行某过程并返回值 如果出现异常则返回另一分支的值
    public static <T> ChoiceResult<T> choice(Produce<T> tryProduce, Offer<T> ifError) {
        try {
            return new ChoiceResult<>(true, tryProduce.call());
        } catch (Exception e) {
            return new ChoiceResult<>(false, ifError.call());
        }
    }

    // choice 方法的返回值 包含执行的结果和发现异常的标志
    public static class ChoiceResult<T> {
        private final boolean success;
        private final T result;
        private ChoiceResult(boolean isSuccess, T result) {
            this.success = isSuccess;
            this.result = result;
        }
        public boolean isSuccess() { return success; }
        public boolean hasException() {
            return !success;
        }
        public T getResult() { return result; }
    }

    public static void main(String[] args) {
        Optional<Integer> o = Try.ignoreGet(() -> 0 / 0);
        System.out.println(o.orElse(-1));
    }
}
